unit SimGrid_Form;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, StdCtrls, BitGrid, ExtCtrls, ComCtrls;

const
  xsize    = 6;  // these could be dynamic at some later date
  ysize    = 10;  // byte wide ops?

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Exit1: TMenuItem;
    Timer1: TTimer;
    StatusBar1: TStatusBar;
    Help1: TMenuItem;
    About1: TMenuItem;
    Open1: TMenuItem;
    Save1: TMenuItem;
    N1: TMenuItem;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    procedure Exit1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure NorthClick(Sender: TObject);
    procedure WestClick( Sender: TObject);
    procedure SouthClick(Sender: TObject);
    procedure EastClick( Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Open1Click(Sender: TObject);
    procedure Save1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  EditGrid  : Array of Array of TEdit;
  CheckGrid : Array of Array of Array[Direction] of TCheckbox;
  CellGrid  : Array of Array of tBitCell;
  FileName  : String;
  FileSaved : Boolean;

implementation

{$R *.DFM}

procedure TForm1.Exit1Click(Sender: TObject);
begin
  Application.Terminate;
end;


procedure TForm1.FormCreate(Sender: TObject);
const
  xspace   = 150;
  yspace   =  48;
var
  x,y      : integer;
begin
  FileName  := 'untitled.grid';
  FileSaved := False;
  setlength(EditGrid,xsize);
  setlength(CheckGrid,xsize);
  setlength(CellGrid,xsize);
  for x := 0 to xsize-1 do
  begin
    setlength(EditGrid[x],ysize);
    setlength(CheckGrid[x],ysize);
    setlength(CellGrid[x],ysize);
    for y := 0 to ysize-1 do
    begin
      CellGrid[x,y] := tBitCell.Create;
      cellGrid[x,y].asHex := Passthrough; // default to passthrough code

      CheckGrid[x,y,north] := TCheckBox.Create(form1);
      CheckGrid[x,y,north].Left :=  54 + (X *  xspace);
      CheckGrid[x,y,north].Top  :=   2 + (Y *  yspace);
      CheckGrid[x,y,north].OnClick := NorthClick;
      CheckGrid[x,y,north].tag  := integer(cellgrid[x,y]);
      CheckGrid[x,y,north].Width := 16;
      CellGrid[x,y].Input[North] := CheckGrid[x,y,north].Checked;
      Form1.InsertControl(CheckGrid[x,y,North]);

      CheckGrid[x,y,west ] := TCheckBox.Create(form1);
      CheckGrid[x,y,west ].Left :=   2 + (X *  xspace);
      CheckGrid[x,y,west ].Top  :=  28 + (Y *  yspace);
      CheckGrid[x,y,west ].OnClick := WestClick;
      CheckGrid[x,y,west ].tag  := integer(cellGrid[x,y]);
      CheckGrid[x,y,west ].Width := 16;
      CellGrid[x,y].Input[West] := CheckGrid[x,y,West].Checked;
      Form1.InsertControl(CheckGrid[x,y,West]);

      CheckGrid[x,y,south] := TCheckBox.Create(form1);
      CheckGrid[x,y,south].Left :=  78 + (X *  xspace);
      CheckGrid[x,y,south].Top  :=  40 + (Y *  yspace);
      CheckGrid[x,y,south].OnClick := SouthClick;
      CheckGrid[x,y,south].tag  := integer(cellGrid[x,y]);
      CheckGrid[x,y,south].Width := 16;
      CellGrid[x,y].Input[South] := CheckGrid[x,y,south].checked;
      Form1.InsertControl(CheckGrid[x,y,South]);

      CheckGrid[x,y,east ] := TCheckBox.Create(form1);
      CheckGrid[x,y,east ].Left := 140 + (X *  xspace);
      CheckGrid[x,y,east ].Top  :=  12 + (Y *  yspace);
      CheckGrid[x,y,east ].OnClick := EastClick;
      CheckGrid[x,y,east ].tag  := integer(cellGrid[x,y]);
      CheckGrid[x,y,east ].Width := 16;
      CellGrid[x,y].Input[East] := CheckGrid[x,y,East].Checked;
      Form1.InsertControl(CheckGrid[x,y,East]);

      EditGrid[x,y] := TEdit.Create(Form1);
      EditGrid[x,y].Left  := 18 + (X *  xspace);
      EditGrid[x,y].Top   := 18 + (Y *  yspace);
      EditGrid[x,y].Text  := '048c159d26ae37bf';  // default to passthrough code
      EditGrid[x,y].OnChange := Edit1Change;
      EditGrid[x,y].Tag := Integer(CellGrid[x,y]);
      Form1.InsertControl(EditGrid[x,y]);
    end;
  end;
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
  With Tedit(Sender) do
  begin
    If Tag <> 0 then
    begin
      tBitCell(Tag).AsHex := Text;
    end;
  end;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  With TCheckBox(Sender) do
    If Tag <> 0 then
    begin
      Boolean(addr(tag)^) := checked;
    end;
end;

procedure TForm1.NorthClick(Sender: TObject);
begin
  With TCheckBox(Sender) do
    If Tag <> 0 then
      tBitCell(tag).Input[North] := checked;
end;

procedure TForm1.WestClick(Sender: TObject);
begin
  With TCheckBox(Sender) do
    If Tag <> 0 then
      tBitCell(tag).Input[West] := checked;
end;

procedure TForm1.SouthClick(Sender: TObject);
begin
  With TCheckBox(Sender) do
    If Tag <> 0 then
      tBitCell(tag).Input[South] := checked;
end;

procedure TForm1.EastClick(Sender: TObject);
begin
  With TCheckBox(Sender) do
    If Tag <> 0 then
      tBitCell(tag).Input[East] := checked;
end;


procedure TForm1.Timer1Timer(Sender: TObject);
const
  InputCost  = 0.20;  // picoJoules
  OutputCost = 1.10;  // picoJoules
var
  TotalEnergy : Double;
  x, y : integer;
begin
  for x := 0 to xsize - 2 do
    for y := 0 to ysize - 1 do
      CheckGrid[x+1,y,West].Checked := CellGrid[x,y].Output[East];
  for x := xsize - 2 downto 0 do
    for y := 0 to ysize - 1 do
      CheckGrid[x,y,East].Checked := CellGrid[x+1,y].Output[West];

  for x := 0 to xsize - 1 do
  begin
    for y := 0 to ysize - 2 do
      CheckGrid[x,y+1,North].Checked := CellGrid[x,y].Output[South];
    for y := ysize - 2 downto 0 do
      CheckGrid[x,y,South].Checked := CellGrid[x,y+1].Output[North];
  end;

  TotalEnergy := BitGrid.InputCount * InputCost +
                 BitGrid.OutputCount * OutputCost;
  StatusBar1.Panels[0].Text := Format('Input Transistions: %d',[BitGrid.InputCount]);
  StatusBar1.Panels[1].Text := Format('Output Transitions: %d',[BitGrid.OutputCount]);
  StatusBar1.Panels[2].Text := Format('Energy Used : %f picoJoule',[TotalEnergy]);
end;

procedure TForm1.Open1Click(Sender: TObject);
var
  f : textfile;
  x,y,i : integer;
  s,t : string;
begin
  If OpenDialog1.Execute then
  begin
    FileName := OpenDialog1.FileName;
    Form1.Caption := 'SimGrid - '+Filename;
    y := 0;
    AssignFile(f,filename);
    Reset(f);
    While Not Eof(f) do
    begin
      x := 0;
      readln(f,s);
      while s <> '' do
      begin
        i := pos(',',s);
        if i <> 0 then
        begin
          t := copy(s,1,i-1);
          delete(s,1,i);
        end
        else
        begin
          t := s;
          s := '';
        end;
        if (x < xsize) and (y < ysize) then
        begin
          CellGrid[x,y].AsHex := t;
          EditGrid[x,y].Text  := CellGrid[x,y].AsHex;
        end;
        inc(x);
      end;
      inc(y);
    end;
    closefile(f);
    FileSaved := True; { we just opened it, we don't need to save it }
  end;
end;

procedure TForm1.Save1Click(Sender: TObject);
var
  f : textfile;
  x,y : integer;
begin
  If SaveDialog1.Execute then
  begin
    filename := SaveDialog1.filename;
    Form1.Caption := 'SimGrid - '+Filename;
    AssignFile(f,filename);
    Rewrite(f);
    for y := 0 to ysize-1 do
    begin
      for x := 0 to xsize -1 do
      begin
        write(f,CellGrid[x,y].AsHex);
        if x < (xsize -1) then write(f,',');
      end;
      writeln(f);
    end;
    closefile(f);
    FileSaved := True;
  end;
end;

end.
